"""
基本数据结构CRUD操作            dir(数据结构对象) 可查询该对象有哪些函数
"""
import random


# list（列表）
def my_list():
    """
    list（列表）的 Create（增加）操作
    """
    # +和+=  效果一样
    old_list = [1, 2]
    new_list = old_list + [3, 4]
    test_list = [1, 2]
    test_list += [3, 4]
    print(f'通过 + 更新后的列表为：{new_list}')
    print(f'通过 += 更新后的列表为：{test_list}')

    # *和*=  效果一样
    new_list = old_list * 3
    test_list *= 3
    print(f'通过 * 更新后的列表为：{new_list}')
    print(f'通过 *= 更新后的列表为：{test_list}')

    # 列表是容器序列，存的是任意类型对象的引用，引用即是内存地址的指针，比如 x=1, x可理解为引用
    x = 'a'
    y = '你'
    list_x = ['a'] * 3
    list_y = ['你'] * 3
    print(f'列表复制的是引用，复制后的列表list_x为：：{list_x},内存地址为：{id(list_x)}')
    print(f'列表复制的是引用，复制后的列表list_y为：：{list_y},内存地址为：{id(list_y)}')
    # 因为Python中有常量池，里面包含数字和英文字符，所以 'a' 和 x的内存地址是相同的，但不包含类似中文字符
    print(f"x的内存地址为：{id(x)}，'a'的内存地址为：{id(list_x[0])}, 二者内存地址是否相同？{id(x) == id(list_x[0])}")
    print(f"y的内存地址为：{id(y)}, '你'的内存地址为：{id(list_y[0])}, 二者内存地址是否相同？{id(y) == id(list_y[0])}")

    # append(添加) 将元素插入到list末尾，list对象内存地址不变
    list_y.append('append')
    print(f'通过 append 后的列表为：{list_y}，内存地址为：{id(list_y)}')

    # insert(插入) 指定位置插入元素，list对象内存地址不变
    list_y.insert(1, 'insert')
    try:
        list_y.insert(list_y.index('append'), '我是在指定元素前面插入的')
    except ValueError as e:
        print(f'指定的元素不在该列表中哦，错误信息为：{e}')
    print(f'通过 insert 后的列表为：{list_y}，内存地址为：{id(list_y)}')
    print("-------------------------------------------------------------------------------------------------------")

    """
    list（列表）的 Retrieve（检索）操作
    """
    # 索引取值
    if 10 > len(list_y) > 0:
        print(f'随机取出 list_y 列表的其中一位元素：{list_y[random.randint(0, len(list_y)-1)]}')
    else:
        print('当前列表长度大于10啦~ 我就不取值咯！')

    # 切片  右闭区间（因为索引是从0开始的）
    # your_list[start:end]  start不指定：从开始切片   end不指定：切片到末尾   二者都不指定：从开始到结尾
    print(f'取出 list_y 列表的第二个及其之后的所有元素：{list_y[1:]}')
    print(f'取出 list_y 列表的第4个及其之前的所有元素：{list_y[:4]}')
    print(f'取出 list_y 列表所有元素：{list_y[:]}')
    # your_list[-1]取出列表最后一位元素
    print(f'取出 list_y 列表最后一位元素：{list_y[-1]}')
    # 间隔  your_list[start:end:step]
    list_step = list(range(100))
    print(f'以间隔为3取出 list_step 列表的所有元素：{list_step[::3]}')

    # index（索引） 返回第一个目标值的索引，无结果会报错
    try:
        print(list_y.index('你'))
    except ValueError as e:
        print(f'未找到该元素哦~，错误信息为：{e}')
    print("-------------------------------------------------------------------------------------------------------")

    """
    list（列表）的 Update（更新）操作
    """
    list_update = ['a', 'b', 'c', 'd', 'e']
    # 单个元素赋值：your_list[index] = x
    list_update[1] = 'update_data'
    print(f'单个元素赋值的结果为：{list_update}')
    # 切片赋值：your_list[start:end] = [x]     can only assign an iterable（赋值必须是可迭代的对象）
    list_update[2:4] = ['我是切片赋值']
    print(f'切片赋值后的结果为：{list_update}')
    print("-------------------------------------------------------------------------------------------------------")

    """
    list（列表）的 Delete（删除）操作
    """
    # pop()  删除末尾元素并返回
    list_delete = ['a', 'a', 'c', 'd', 'e']
    print(f'pop后的元素为：{list_delete.pop()}')
    # remove()  删除元素但是不返回，只删除找到的第一个目标元素
    list_delete.remove('a')
    print(f"remove后的列表为：{list_delete}")
    print("-------------------------------------------------------------------------------------------------------")

    """
    list（列表）的 统计和排序操作
    """
    # 计算目标元素在当前list中的个数（实际用的很少）
    list_count = ['a', 'a', 'c', 'd', 'e']
    print(f"'a'元素在当前list中的个数为：{list_count.count('a')}")

    # reverse 在当前列表上做反转，返回None
    list_reverse = [2, 9, 1, 2, 7, 3, 5]
    list_reverse.reverse()
    print(f'reverse后的结果为：{list_reverse}')
    # reversed 返回新列表
    print(f'reversed后的新列表为：{list(reversed(list_reverse))}')
    # sort 在当前列表上做增序排列， 返回None
    list_sort = [2, 9, 1, 2, 7, 3, 5]
    list_sort.sort()
    print(f'sort增序后的结果为：{list_sort}')
    # your_list.sort(reversed = False)  倒序排列   默认是False
    list_sort.sort(reverse=True)
    print(f'倒序后的列表为：{list_sort}')
    # sorted 返回新列表
    print(f'sorted后的新列表为：{list(sorted(list_sort))}')
    # * your_list.sort(key=func)  func是函数，也就是自定义排序规则  后面会讲
    print("-------------------------------------------------------------------------------------------------------")
    return None


# Tuple（元组）  可以看作是不可修改的列表
def my_tuple():
    """
    Tuple（元组）的 Retrieve（检索）操作
    """
    # 索引取值
    tuple_test = (1, 2, 3, 3, 'a')
    print(f'最后一个元素为：{tuple_test[-1]}')

    # 切片  右闭区间    不管怎么测试不会报错，最多返回空元组
    print(f'切片范围1:4的结果为：{tuple_test[-4:-1]}')

    # index 返回第一个目标的索引值
    try:
        print(f"元素3返回的索引值为：{tuple_test.index(4)}")
    except ValueError as e:
        print(f'未找到该元素：{e}')
    print("-------------------------------------------------------------------------------------------------------")
    return None


# Dict（字典）
def my_dict():
    """
    Dict（字典）的 Create（增加）操作
    """
    # 键对值赋值
    dict_test = {}
    dict_test['a'] = 1
    print(dict_test)

    # update 合并两个字典 重复的key会覆盖前面的  返回None   dict_test1合并后内存地址不变
    dict_test1 = {'a': 2}
    dict_test1.update(dict_test)
    print(f'合并 dict_test 和 dict_test1的结果为：{dict_test1}')

    # setdefault  如果字典没有该键对值，则设置默认值(添加操作)，如果字典有该键对值（键相同），则pass
    dict_test1.setdefault('key', 'default_value')
    dict_test1.setdefault('a', 121)
    print(f'setdefault后的值{dict_test1}')
    print("-------------------------------------------------------------------------------------------------------")

    """
    Dict（字典）的 Retrieve操作
    """
    # 通过键来访问
    print(f"通过键访问值：{dict_test1['a']}")

    # get 如果有值，则返回该值   如果没有值，则返回默认值   不会报错
    print(f'通过get函数获取值，可设置默认值：{dict_test1.get("w", "default_value")}')

    # keys  返回所有的key
    print(f'返回dict_test1所有的key:{dict_test1.keys()}')
    # values  返回所有的value
    print(f'返回dict_test1所有的value:{dict_test1.values()}')
    # items  返回所有的item   元组形式的键对值
    print(f'返回dict_test1所有的item:{dict_test1.items()}')
    print("-------------------------------------------------------------------------------------------------------")

    """
    Dict（字典）的 Update操作
    """
    # 键对值赋值   重复key的时候，value会覆盖前面的
    dict_test1['a'] = 9
    print(f'键对值赋值后的结果为：{dict_test1}')

    # update  可以新增键值对，也可以修改相同key的value（即覆盖前面的）      返回None
    dict_test1.update({'a': 10, 'update': '我是新增的'})
    print(f'update后的字典为：{dict_test1}')
    print("-------------------------------------------------------------------------------------------------------")

    """
    Dict（字典）的 Delete操作
    """
    # pop(key)   删除指定key  返回删除的 key 对应的 value
    print(f'pop删除指定key对应的value为：{dict_test1.pop("a")}')

    # popitem() 字典是无序的，所以是随机删除一个元素   *** 尽量不要用，产生莫名的bug
    print(f'popitem随机删除的元素是：{dict_test1.popitem()}')

    # clear() 清空当前的字典  一般很少用，除非要求这个字典的内存地址不要变才使用   返回None
    dict_test1.clear()
    print(f'clear后的字典为：{dict_test1}')
    print("-------------------------------------------------------------------------------------------------------")
    return None


# Set（集合）  可以看作没有value的字典   无序
def my_set():
    """
    Set（集合）的 Create操作
    """
    # add  新增集合元素   新建一个set集合需要使用  set()
    set_test = set()
    set_test.add(1)
    set_test.add('1')
    set_test.add((1,))
    print(f'新增后的set集合为：{set_test}')
    print("-------------------------------------------------------------------------------------------------------")

    """
    Set（集合）的 Retrieve操作
    """
    # in 判断当前元素在不在set中   x in your_set
    print(f'当前元素是否在该set中？{(1,) in set_test}')
    print("-------------------------------------------------------------------------------------------------------")

    """
    Set（集合）的 Update操作
    """
    # x.update(y) 合并x、y两个set集合   返回None  x集合发生改变，y不变
    set_test.update({1, 2, (2,), '1'})
    print(f'合并后的集合为：{set_test}')

    # x.union(y) 合并两个set集合   返回两个set集合的并集，x、y两个集合不发生改变
    set_union = set_test.union({'x', 'y', 'z'})
    print(f'union合并后的集合为：{set_union}')
    print("-------------------------------------------------------------------------------------------------------")

    """
    Set（集合）的 Delete操作
    """
    # remove 删除元素，没有该元素会报错
    set_delete = {1, 2, (2,), '1'}
    try:
        set_delete.remove(10)
        print(f'remove一个元素后的集合为：{set_delete}')
    except KeyError as e:
        print(f'没有{e}这个元素，删除个球？')

    # discard 删除元素，没有该元素不会报错
    set_delete.discard('dis')
    print(f'discard一个元素后的集合为：{set_delete}')

    # pop 随机删除一个元素
    for i in range(5):
        try:
            print(f'pop随机删除的元素为：{set_delete.pop()}')
        except KeyError as e:
            print(f'集合都空了，还删？{e}')
    return None


if __name__ == '__main__':
    my_list()
    my_tuple()
    my_dict()
    my_set()
